<?php
/**
 * @Description procJSON的php实现
 * @Sonkwl Xiong
 * @Date 2021/12/29 09:26:03
 */
//@Sonkwl Xiong 2022/02/22 08:57:37
//@Desc 新增开放模型(无需jwt验证)
class procJSON{
    static public $json=array();//post
    static public $PDO="mysql:host=10.202.8.204;dbname=xczx";
	static public $user="test";
	static public $pwd="test";
  
    static public $db_tables=array();

    static public $apps=array();//app编号
    static public $app_table=array();
    static public $session_no='@ALL';
    static public $keystr='WHSS';
    static public $keyint=7;
    static public $jwt="";//jwt版本
    static public $exp="";

    //@Desc token解析
    static public function CheckToken($token){
        if($tokenjson=jwt::CheckJWT($token,self::$keystr)){
            self::$session_no=$tokenjson["id"];
        }else if($tokenarray=jwt::CheckJWTV1($token,self::$keystr,self::$keyint)){
            self::$session_no=$tokenarray[0];
        }else{
            self::RES("NG","token已经过期");
        }
    }

    //@Desc 输出
    static public function RES($res,$message){
        if($res=="NG"){
            self::$json=array();
        }
        self::$json["res"]= htmlspecialchars($res,ENT_NOQUOTES);
        self::$json["message"]=htmlspecialchars($message,ENT_NOQUOTES);
        echo json_encode(self::$json,JSON_UNESCAPED_UNICODE);
        exit;
    }

    //@Desc 解析json数据
    static public function DecodePost(){
        if($_SERVER["REQUEST_METHOD"]!="POST"){
            echo 'error 404';
            exit;
        }
        $command = isset($GLOBALS['HTTP_RAW_POST_DATA'])?$GLOBALS['HTTP_RAW_POST_DATA']:file_get_contents("php://input");
        $command=str_replace("'","''",$command);
        self::$json=(array)json_decode($command,true);//true,转化成数组
        //print_r(self::$json);
        if(count(self::$json)==0){
            self::RES("NG","输入参数错误，必须是JSON格式");
        }
    }

    //@Desc PDO初始化
    static public function GetPDO(){
        try{
			$db=new PDO(self::$PDO,self::$user,self::$pwd);
			return $db;
		}catch(PDOException $e){
            self::RES("NG",$e->getMessage());
		}
    }

    //@Desc JWT
    static public function JWT($db,$step,$json){
        if($json["command"]!="jwt"){
            return;
        }

        self::CheckToken($json["token"]);
        //验证用户是否有app权限
        if(count(self::$apps)>0 && count(self::$app_table)>0){
            if(!isset(self::$app_table["priv"]) || !isset(self::$app_table["table"]) || !isset(self::$app_table["id"])){
                self::RES("NG","验证用户是否有访问权限，需要定义app_table");
            }
            $check=0;
            $dbh=$db->prepare("select ? from ? where ?=?;");
            $dbh->execute(self::$app_table["priv"],self::$app_table["table"],self::$app_table["id"], htmlentities(self::$session_no));
            $rs=$dbh->fetchAll(PDO::FETCH_NUM);
            foreach ($rs as $key => $row) {
                if(in_array($row[0],self::$apps)){
                    $check++;
                }
            }
            if($check==0){
                self::RES("NG","用户[".self::$session_no."]没有权限访问该资源");
            }
        }
    }

    //@Desc login操作
    static public function Login($db,$step,$json){
        if($json["command"]!="login"){
            return;
        }

        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],1);//强制=
        $table_clause=$where["where"];
        $table_value=$where["params"];

        $sql="select count(*) from ".$table_name.$table_clause;
        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);
        $rs=$dbh->fetchAll();
        
        if(count($rs)==0){
            self::RES("NG","登录失败");
        }
        self::$json[$step]["token"]=jwt::SetJWT($json["clause"][$json["id"]],self::$exp,self::$keystr);
        if(self::$jwt=="V1"){
            self::$json[$step]["token"]=jwt::SetJWTV1($json["clause"][$json["id"]],self::$exp,self::$keystr,self::$keyint);
        }
    }
    
    //@Desc 单笔查询
    static public function Query($db,$step,$json){
        if($json["command"]!="query"){
            return;
        }

        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],0);
        $table_clause=$where["where"];
        $table_value=$where["params"];

        $sql="select ".(isset($json["column"])?$json["column"]:"*")." from ".$table_name.$table_clause;
     
        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);
        $rs=$dbh->fetchAll(PDO::FETCH_ASSOC);
        //echo $sql; exit;
        if(count($rs)==0){
            //@Sonkwl Xiong 2022/01/06 08:02:42
            //@Desc 验证数据不存在
            if(!isset($json["exists"]) || $json["exists"]!="NONE"){
                self::RES("NG","数据不存在,操作终止");
            }
        }else{
            if(isset($json["exists"]) && $json["exists"]=="NONE"){
                self::RES("NG","数据存在,操作终止");
            }
            self::$json[$step]["clause"]=$rs[0];
        }
    }

    //@Desc 多笔查询
    static public function Select($db,$step,$json){
        if($json["command"]!="select"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],0);
        $table_clause=$where["where"];
        $table_value=$where["params"];
        
        $page=isset($json["page"])?$json["page"]:1;
        $slice=isset($json["slice"])?$json["slice"]:10;
        $table_order=isset($json["order"])?' order by '.$json["order"]:"";
        $table_limit=" limit ".($page*$slice-$slice).",".$slice;
        if($slice==0){
            //全表查询
            $table_limit="";
        }
        $sql="select ".(isset($json["column"])?$json["column"]:"*")." from ".$table_name.$table_clause.$table_order.$table_limit;

        
        $sql_count="select count(*) from ".$table_name.$table_clause;
        $rows=0;
        $pages=0;

        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);
        $list=$dbh->fetchAll(PDO::FETCH_ASSOC);

        if($slice!=0){
            $dbh=$db->prepare($sql_count);
            $dbh->execute($table_value);
            $rs=$dbh->fetchAll();
            $rows=$rs[0][0];
            $pages=(int)($rows/$slice)+($rows%$slice?1:0);
        }
        
        self::$json[$step]["list"]=$list;
        self::$json[$step]["rows"]=$rows;
        self::$json[$step]["pages"]=$pages;
        self::$json[$step]["page"]=$page;
    }

    //@Desc 新增操作
    static public function Insert($db,$step,$json){
        if($json["command"]!="insert"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        $val=array();
        foreach ($json["clause"] as $key => $value) {
            array_push($val,"?");
            $json["clause"][htmlentities($key)]=$value;
        }
        $sql="insert into ".$table_name."(".implode(",",array_keys($json["clause"])).") values(". implode(",",$val).");";
        $dbh=$db->prepare($sql);
        $dbh->execute(array_values($json["clause"]));
    }

    //@Desc 更新操作
    static public function Update($db,$step,$json){
        if($json["command"]!="update"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],1);
        $table_clause=$where["where"];
        $table_value=$where["params"];
  
        $table_update=' set ';
        $val=array();
        foreach ($json["update"] as $column => $value) {
            $table_update.= htmlentities($column)."=?,";//强制=
            array_push($val,self::HandlerValue($value));
        }
        $table_update=trim($table_update,",");
        if($table_clause==""){
            self::RES("NG","更新操作，clause必须有数据");
        }

        //$val=array_values($json["update"]);
        foreach ($table_value as $key => $value) {
            array_push($val,self::HandlerValue($value));
        }
        //print_r($val); exit;
        $sql="update ".$table_name.$table_update.$table_clause;
        //echo $sql;
        $dbh=$db->prepare($sql);
        $dbh->execute($val);
    }

    //@Desc 删除操作
    static public function Delete($db,$step,$json){
        if($json["command"]!="delete"){
            return;
        }
        $table_name=self::HandlerTable($json["table"]);
        $where=self::HandlerWhere($json["clause"],1);
        $table_clause=$where["where"];
        $table_value=$where["params"];

        if($table_clause==""){
            self::RES("NG","刪除操作，clause必须有数据");
        }

        $sql="delete from ".$table_name.$table_clause;
        $dbh=$db->prepare($sql);
        $dbh->execute($table_value);
    }

    //@Desc 特殊值
    static public function HandlerValue($value){
        $value=$value==="@token"?self::$session_no:$value;
        $value=$value==="@time"?date("Y-m-d H:i:s"):$value;
        $value=$value==="@date"?date("Y-m-d"):$value;
        $value=$value==="@NULL"?"":$value;//值为空
        return $value;
    }

    //@desc 验证db_table
    static public function HandlerTable($tbl){
        if(!isset(self::$db_tables[$tbl])){
            self::RES("NG","[".$tbl."]的对应表不存在");
        }
        return self::$db_tables[$tbl];
    }

    //$Desc 验证数据
    static public function CheckInput($val){
        $regex="/^\w+(_|\w+)$/";
        if(!preg_match($regex,$val)){
            self::RES("NG",$val."不符合规则");
        }
        return $val;
    }

    //@Desc 获得DML where部分
    static public function HandlerWhere($clause,$mod){
        $table_where='';
        $params=array();
        foreach($clause as $key=>$value){
            $key=self::CheckInput($key);
            if($value==""){
                continue;
            }
            if(is_array($value)){
                if(count($value)==0){
                    continue;
                }
                //between
                if(count($value)==3 && $value[0]=="between"){
                    $table_where.=($table_where==""?" where ":" and ").$key." ? and ?";
                    array_push($params,self::HandlerValue($value[1]));
                    array_push($params,self::HandlerValue($value[2]));
                    continue;
                }
                //in
                $val=array();
                for($i=0;$i<count($value);$i++){
                    array_push($val,"?");
                    array_push($params,self::HandlerValue($value[$i]));
                }
                $table_where.=($table_where==""?" where ":" and ").$key." in(".implode(",",$val).")";
                continue;
            }
            if($mod==1){
                //强制等于,不存在like
                $table_where.=($table_where==""?" where ":" and ").$key."= ?";
                array_push($params,self::HandlerValue($value));
                continue;
            }
            //非强制模块，允许like查询
            $table_where.=($table_where==""?" where ":" and ").$key.(strstr($value,"%")?" like ":"=")."?";
            array_push($params,self::HandlerValue($value));
        }
        return array(
            "where"=>$table_where,
            "params"=>$params
        );
    }

    //@Desc 运行框架
    static public function Run(){
        self::DecodePost();
        $db=self::GetPDO();
        try{
            $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $db->beginTransaction();
            foreach(self::$json as $step=>$json){
                if($step=="res" || $step=="message"){
                    // 跳过返回值
                    continue;
                }
                //验证请求模型
                procModel::CheckCommand($json);
                //验证开放模型
                procModel::CheckOpen($json,self::$session_no);

                self::Login($db,$step,$json);
                self::JWT($db,$step,$json);
                self::Query($db,$step,$json);
                self::Select($db,$step,$json);
                self::Insert($db,$step,$json);
                self::Update($db,$step,$json);
                self::Delete($db,$step,$json);
            }
            $db->commit();
            self::RES("OK","操作成功");
        }catch(Exception $e){
            $db->rollBack();
            self::RES("NG",$e->getMessage());
        }
    }
}
?>